﻿//
// (C) Copyright 2009 Irantha Suwandarathna (iranthas@hotmail.com)
// All rights reserved.
//

/* Copyright (c) 2001-2008, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use _in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions _in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer _in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EffiProz.Core.Rights;
using EffiProz.Core.Lib;
using EffiProz.Core.Errors;

namespace EffiProz.Core
{
    public class Schema : SchemaObject
    {
        public QNameManager.QName name;
        public SchemaObjectSet triggerLookup;
        public SchemaObjectSet constraintLookup;
        public SchemaObjectSet indexLookup;
        public SchemaObjectSet tableLookup;
        public SchemaObjectSet sequenceLookup;
        public SchemaObjectSet typeLookup;
        public SchemaObjectSet charsetLookup;
        public SchemaObjectSet collationLookup;
        public SchemaObjectSet procedureLookup;
        public SchemaObjectSet functionLookup;
        public SchemaObjectSet specificRoutineLookup;
        public SchemaObjectSet assertionLookup;
        public HashMappedList tableList;
        public HashMappedList sequenceList;
        public Grantee owner;

        public Schema(QNameManager.QName name, Grantee owner)
        {

            this.name = name;
            triggerLookup = new SchemaObjectSet(SchemaObjectTypes.TRIGGER);
            indexLookup = new SchemaObjectSet(SchemaObjectTypes.INDEX);
            constraintLookup = new SchemaObjectSet(SchemaObjectTypes.CONSTRAINT);
            tableLookup = new SchemaObjectSet(SchemaObjectTypes.TABLE);
            sequenceLookup = new SchemaObjectSet(SchemaObjectTypes.SEQUENCE);
            typeLookup = new SchemaObjectSet(SchemaObjectTypes.TYPE);
            charsetLookup = new SchemaObjectSet(SchemaObjectTypes.CHARSET);
            collationLookup = new SchemaObjectSet(SchemaObjectTypes.COLLATION);
            procedureLookup = new SchemaObjectSet(SchemaObjectTypes.PROCEDURE);
            functionLookup = new SchemaObjectSet(SchemaObjectTypes.FUNCTION);
            specificRoutineLookup = new SchemaObjectSet(SchemaObjectTypes.SPECIFIC_ROUTINE);
            assertionLookup = new SchemaObjectSet(SchemaObjectTypes.ASSERTION);
            tableList = (HashMappedList)tableLookup.map;
            sequenceList = (HashMappedList)sequenceLookup.map;
            this.owner = owner;
            name.owner = owner;
        }

        public int getType()
        {
            return SchemaObjectTypes.SCHEMA;
        }

        public QNameManager.QName getName()
        {
            return name;
        }

        public QNameManager.QName getSchemaName()
        {
            return null;
        }

        public QNameManager.QName getCatalogName()
        {
            return null;
        }

        public Grantee getOwner()
        {
            return owner;
        }

        public OrderedHashSet getReferences()
        {
            return new OrderedHashSet();
        }

        public OrderedHashSet getComponents()
        {
            return null;
        }

        public void compile(Session session, SchemaObject parentObject) { }

        public String getSQL()
        {

            StringBuilder sb = new StringBuilder(128);

            sb.Append(Tokens.T_CREATE).Append(' ');
            sb.Append(Tokens.T_SCHEMA).Append(' ');
            sb.Append(name.statementName).Append(' ');
            sb.Append(Tokens.T_AUTHORIZATION).Append(' ');
            sb.Append(owner.getStatementName());

            return sb.ToString();
        }

        public String[] getSQLArray(OrderedHashSet resolved,
                                    OrderedHashSet unresolved)
        {

            EfzArrayList list = new EfzArrayList();
            StringBuilder sb = new StringBuilder(128);

            sb.Append(Tokens.T_CREATE).Append(' ');
            sb.Append(Tokens.T_SCHEMA).Append(' ');
            sb.Append(name.statementName).Append(' ');
            sb.Append(Tokens.T_AUTHORIZATION).Append(' ');
            sb.Append(owner.getStatementName());
            list.add(sb.ToString());
            sb.Length = (0);
            sb.Append(Tokens.T_SET).Append(' ');
            sb.Append(Tokens.T_SCHEMA).Append(' ');
            sb.Append(name.statementName);
            list.add(sb.ToString());

            //
            String[] subList;

            subList = charsetLookup.getSQL(resolved, unresolved);

            list.addAll(subList);

            subList = collationLookup.getSQL(resolved, unresolved);

            list.addAll(subList);

            subList = typeLookup.getSQL(resolved, unresolved);

            list.addAll(subList);

            subList = sequenceLookup.getSQL(resolved, unresolved);

            list.addAll(subList);

            subList = tableLookup.getSQL(resolved, unresolved);

            list.addAll(subList);

            subList = functionLookup.getSQL(resolved, unresolved);

            list.addAll(subList);

            subList = procedureLookup.getSQL(resolved, unresolved);

            list.addAll(subList);

            subList = assertionLookup.getSQL(resolved, unresolved);

            list.addAll(subList);

            //
            String[] array = new String[list.size()];

            list.toArray(array);

            return array;
        }

        public String[] getSequenceRestartSQL()
        {

            EfzArrayList list = new EfzArrayList();
            Iterator it = sequenceLookup.map.values().iterator();

            while (it.hasNext())
            {
                NumberSequence sequence = (NumberSequence)it.next();
                String ddl = sequence.getRestartSQL();

                list.add(ddl);
            }

            String[] array = new String[list.size()];

            list.toArray(array);

            return array;
        }

        public String[] getTriggerSQL()
        {

            EfzArrayList list = new EfzArrayList();
            Iterator it = tableLookup.map.values().iterator();

            while (it.hasNext())
            {
                Table table = (Table)it.next();
                String[] ddl = table.getTriggerSQL();

                list.addAll(ddl);
            }

            String[] array = new String[list.size()];

            list.toArray(array);

            return array;
        }

       public bool isEmpty()
        {
            return sequenceList.isEmpty() && tableList.isEmpty();
        }

       public Iterator schemaObjectIterator(int type)
        {

            switch (type)
            {

                case SchemaObjectTypes.SEQUENCE:
                    return sequenceLookup.map.values().iterator();

                case SchemaObjectTypes.TABLE:
                case SchemaObjectTypes.VIEW:
                    return tableLookup.map.values().iterator();

                case SchemaObjectTypes.CHARSET:
                    return charsetLookup.map.values().iterator();

                case SchemaObjectTypes.COLLATION:
                    return collationLookup.map.values().iterator();

                case SchemaObjectTypes.PROCEDURE:
                    return procedureLookup.map.values().iterator();

                case SchemaObjectTypes.FUNCTION:
                    return functionLookup.map.values().iterator();

                case SchemaObjectTypes.ROUTINE:
                    Iterator functions = functionLookup.map.values().iterator();

                    return new WrapperIterator(
                        functions, procedureLookup.map.values().iterator());

                case SchemaObjectTypes.DOMAIN:
                case SchemaObjectTypes.TYPE:
                    return typeLookup.map.values().iterator();

                case SchemaObjectTypes.ASSERTION:
                    return assertionLookup.map.values().iterator();

                case SchemaObjectTypes.TRIGGER:
                    return triggerLookup.map.values().iterator();

                case SchemaObjectTypes.INDEX:
                    return indexLookup.map.values().iterator();

                case SchemaObjectTypes.CONSTRAINT:
                    return constraintLookup.map.values().iterator();

                default:
                    throw Error.runtimeError(ErrorCode.U_S0500, "Schema");
            }
        }

       public void clearStructures()
        {

            tableList.clear();
            sequenceList.clear();

            triggerLookup = null;
            indexLookup = null;
            constraintLookup = null;
            procedureLookup = null;
            functionLookup = null;
            sequenceLookup = null;
            tableLookup = null;
            typeLookup = null;
        }
    }
}
